﻿using System;
using System.ComponentModel;
using Com.PhilChuang.Pmvp.Ui.Views.Impl.ViewModels;
using Com.PhilChuang.Utils;
using Com.PhilChuang.Utils.Mobile;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Com.PhilChuang.Pmvp.Ui.Views.Impl.Pages
{
	public class PageBase<TViewModel> : PhoneApplicationPage
		where TViewModel : AbstractViewModel
	{
		#region Events
		/// <summary>
		/// Fires once when the page is loaded via the OS (during NavigatedTo, before Shown)
		/// </summary>
		public event Action PageLoaded = delegate { };
		/// <summary>
		/// Fires when the page is shown (during NavigatedTo)
		/// </summary>
		public event Action Shown = delegate { };
		/// <summary>
		/// Fires when the page is hidden before it is unloaded (during NavigatedFrom)
		/// </summary>
		public event Action Hidden = delegate { };
		#endregion

		#region Instance members
		private TViewModel myViewModel;
		#endregion

		#region Properties
		public TViewModel ViewModel
		{
			get { return myViewModel; }
			set
			{
				this.InvokeSet (val =>
				{
					if (myViewModel != null)
					{
						myViewModel.PropertyChanged -= OnViewModelPropertyChanged;
					}

					DataContext = myViewModel = val;

					if (myViewModel != null)
					{
						myViewModel.PropertyChanged += OnViewModelPropertyChanged;
						UpdateApplicationBarItems ();
						OnViewModelAttached ();
					}
				}, value);
			}
		}

		protected bool IsLightTheme
		{
			get { return (System.Windows.Visibility) System.Windows.Application.Current.Resources["PhoneLightThemeVisibility"] == System.Windows.Visibility.Visible; }
		}
		#endregion

		#region Lifecycle
		protected PageBase ()
		{
			DebugWriteLine ("new");
		}

#if DEBUG
		~PageBase()
		{
			DebugWriteLine ("finalize");
		}
#endif

		protected override void OnNavigatedTo (System.Windows.Navigation.NavigationEventArgs e)
		{
			DebugWriteLine ("OnNavigatedTo");
			AppServiceLocator.Instance.GetImpl<NavigationHelper> ().CurrentPage = this;
			var pageHelper = AppServiceLocator.Instance.GetImpl<NavigationHelper> ();
			// make sure presenter is running (this will wire up the page / viewmodel / viewfacade to the presenter, and start the app)
			if (pageHelper.WireToPresenter (this))
				PageLoaded ();
			Shown ();
		}

		protected override void OnNavigatedFrom (System.Windows.Navigation.NavigationEventArgs e)
		{
			DebugWriteLine ("OnNavigatedFrom");
			Hidden ();
			base.OnNavigatedFrom (e);
		}
		#endregion

		#region Functionality
		public void Close ()
		{
			NavigationService.GoBack ();
		}
		#endregion

		#region to implement
		/// <summary>
		/// Manually set the ApplicationBar items because they start off null
		/// </summary>
		protected virtual void SetApplicationBarItems ()
		{
			// does nothing
		}

		protected void SetApplicationBarButtons (ref ApplicationBarIconButton btn1)
		{
			btn1 = (ApplicationBarIconButton) ApplicationBar.Buttons[0];
		}

		protected void SetApplicationBarButtons (ref ApplicationBarIconButton btn1, ref ApplicationBarIconButton btn2)
		{
			SetApplicationBarButtons (ref btn1);
			btn2 = (ApplicationBarIconButton) ApplicationBar.Buttons[1];
		}

		protected void SetApplicationBarButtons (ref ApplicationBarIconButton btn1, ref ApplicationBarIconButton btn2, ref ApplicationBarIconButton btn3)
		{
			SetApplicationBarButtons (ref btn1, ref btn2);
			btn3 = (ApplicationBarIconButton) ApplicationBar.Buttons[2];
		}

		protected void SetApplicationBarButtons (ref ApplicationBarIconButton btn1, ref ApplicationBarIconButton btn2, ref ApplicationBarIconButton btn3, ref ApplicationBarIconButton btn4)
		{
			SetApplicationBarButtons (ref btn1, ref btn2, ref btn3);
			btn4 = (ApplicationBarIconButton) ApplicationBar.Buttons[3];
		}

		protected void SetApplicationBarMenuItems (ref ApplicationBarMenuItem btn1)
		{
			btn1 = (ApplicationBarMenuItem) ApplicationBar.MenuItems[0];
		}

		protected void SetApplicationBarMenuItems (ref ApplicationBarMenuItem btn1, ref ApplicationBarMenuItem btn2)
		{
			SetApplicationBarMenuItems (ref btn1);
			btn2 = (ApplicationBarMenuItem) ApplicationBar.MenuItems[1];
		}

		protected void SetApplicationBarMenuItems (ref ApplicationBarMenuItem btn1, ref ApplicationBarMenuItem btn2, ref ApplicationBarMenuItem btn3)
		{
			SetApplicationBarMenuItems (ref btn1, ref btn2);
			btn3 = (ApplicationBarMenuItem) ApplicationBar.MenuItems[2];
		}

		protected void SetApplicationBarMenuItems (ref ApplicationBarMenuItem btn1, ref ApplicationBarMenuItem btn2, ref ApplicationBarMenuItem btn3, ref ApplicationBarMenuItem btn4)
		{
			SetApplicationBarMenuItems (ref btn1, ref btn2, ref btn3);
			btn4 = (ApplicationBarMenuItem) ApplicationBar.MenuItems[3];
		}

		protected void SetApplicationBarMenuItems (ref ApplicationBarMenuItem btn1, ref ApplicationBarMenuItem btn2, ref ApplicationBarMenuItem btn3, ref ApplicationBarMenuItem btn4, ref ApplicationBarMenuItem btn5)
		{
			SetApplicationBarMenuItems (ref btn1, ref btn2, ref btn3, ref btn4);
			btn5 = (ApplicationBarMenuItem) ApplicationBar.MenuItems[4];
		}

		/// <summary>
		/// Occurs when the ViewModel is attached to the Page, perform manual binding here.
		/// Call base impl first.
		/// </summary>
		protected virtual void OnViewModelAttached ()
		{
			// does nothing
		}

		/// <summary>
		/// Occurs when the ViewModel fires PropertyChanged, perform manual binding here.
		/// Call base impl first.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void OnViewModelPropertyChanged (object sender, PropertyChangedEventArgs e)
		{
			if (UpdateApplicationBarItemsWhen (e.PropertyName))
			{
				UpdateApplicationBarItems ();
			}
		}

		protected virtual bool UpdateApplicationBarItemsWhen (String propertyName)
		{
			return propertyName == INPCHelper.GetPropertyName (() => ViewModel.AllControlsEnabled);
		}

		/// <summary>
		/// Updates ApplicationBar items state from the ViewModel.
		/// Call base at the beginning of any override methods.
		/// </summary>
		protected virtual void UpdateApplicationBarItems ()
		{
			this.SetApplicationBarEnabled (ViewModel.AllControlsEnabled);
		}

		protected void DebugWriteLine (String msg, params Object[] msgArgs)
		{
#if DEBUG
			System.Diagnostics.Debug.WriteLine (String.Format ("[{0}]\t{1}\t{2}", System.Threading.Thread.CurrentThread.ManagedThreadId, GetType ().Name, String.Format (msg, msgArgs)));
#endif
		}
		#endregion
	}
}
